using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;
using Microsoft.Win32;
using UmassGrader.Properties;
using System.Xml.Serialization;
using System.Diagnostics;




namespace UmassGrader
{
    /// <summary>
    /// the main UI window
    /// </summary>
    public partial class Form1 : Form
    {
        /// <summary>
        /// myClassSection holds all data about a class for a semester including:
        /// all students enrolled (or withdrawn),
        /// all programming assignments to be graded
        /// all path information.
        /// </summary>
        public static ClassSection myClassSection;
        /// <summary>
        /// a progress indicator that can be used by any method of form1
        /// </summary>
        public static dlgProgress dlgOutput;

        public static List<Button> myGrdButtons;

        /// <summary>
        /// autogenerated function for the creation of the main form
        /// </summary>
        public Form1()
        {
            InitializeComponent();
            myGrdButtons = new List<Button>();
            myGrdButtons.Add(grd100);
            myGrdButtons.Add(grd95);myGrdButtons.Add(grd90);
            myGrdButtons.Add(grd85);myGrdButtons.Add(grd80);
            myGrdButtons.Add(grd75);myGrdButtons.Add(grd70);
            myGrdButtons.Add(grd65);myGrdButtons.Add(grd60);
            myGrdButtons.Add(grd55);myGrdButtons.Add(grd50);
            myGrdButtons.Add(grd45);myGrdButtons.Add(grd40);
            myGrdButtons.Add(grd35);myGrdButtons.Add(grd30);
            myGrdButtons.Add(grd25);myGrdButtons.Add(grd20);
            myGrdButtons.Add(grd10);
            myGrdButtons.Add(grd0);

        }

        /// <summary>
        /// once all objects have been created this functions give appropriate values to the various
        /// items
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            //System.Collections.IDictionary sp = Environment.GetEnvironmentVariables();
            try
            {
                myClassSection = new ClassSection();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            chkShowWithdrawn.Checked = true;
            chkAutoAdvance.Checked = true;
            chkAutoDelete.Checked = true;
            picStuPic.Image = UmassGrader.Properties.Resources.noPhoto;

            #region setup buttons with user values
            string[] btnList = Settings.Default.grdButtons.Split(',');
            for (int i = 0; i < btnList.Length; i++)
            {
                myGrdButtons[i].Text = btnList[i];
            }
            #endregion

            chkWAR.Checked = Settings.Default.WaitAfterRun;
            txtWARms.Text = Settings.Default.WaitAfterRunMS.ToString();


            /*            
            //HKEY_USERS\S-1-5-21-946338402-2240619745-1135854472-1005\Environment
            //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0 - "InstallDir" 
            //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\"Dbghelp_path"
            //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS - "VS7CommonBinDir"


 */


            #region new path setup
            //setup the Enviroment variables so that CL.exe will run without a hitch
            //a better way exists by grabbing info from the regitry HKLM\Software\microsoft\VisualStudio\8.0\setup\vc
            //9.0 product dir = c:\program files\Microsoft Visual Studio 9.0\vc\
            //8.0 product dir = C:\Program Files\Microsoft Visual Studio 8\VC\
            //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VC
            RegistryKey productpath = Registry.LocalMachine;
            RegistryKey itemPath;
            String vsPath;
            String installPath;
            String subKey,sdkSubkey;
            String ProgPath;
            String sdkPath;
            List<String> versions=new List<String>(4);

            //have we found the verion we want to use?
            if (Settings.Default.VSVer == "")
            {
                #region use 32-64 bit to find the right place in the registry
                //get list of possible versions we can use
                //enumerate all keys under
                //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio
                // then check if they have \setup underthem.
                if (IntPtr.Size == 8)
                {
                    subKey = @"SOFTWARE\WOW6432Node\Microsoft\VisualStudio";
                    sdkSubkey=@"SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows";
                    ProgPath=Environment.GetEnvironmentVariable("ProgramFiles(x86)");
                }
                else if (IntPtr.Size == 4)
                {
                    subKey = @"SOFTWARE\Microsoft\VisualStudio";
                    sdkSubkey = @"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
                    ProgPath = Environment.GetEnvironmentVariable("ProgramFiles");
                }
                else
                {
                    subKey = "";// this could be a problem...
                    sdkSubkey="";
                    ProgPath = "";
                }
                #endregion

                #region get VS VC path
                productpath = Registry.LocalMachine.OpenSubKey(subKey); // TODO: check if visual studio is installed...
                int selected;
                #region build List of installed Visual Studios
                foreach (string subtree in productpath.GetSubKeyNames())
                {
                    //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VC
                    if (
                    (itemPath = productpath.OpenSubKey( subtree + @"\Setup\VC"))
                        !=null)
                        versions.Add(subtree);
                }
                #endregion
                #region find the version the user wants to use
                if (versions.Count == 0)
                {
                    selected = -1;
                    MessageBox.Show("Cant find Visual Studio. Exiting"); 
                    Close();
                }
                else if (versions.Count == 1)
                {
                    selected = 0;
                    MessageBox.Show(String.Format("Detected Visual Studio {0}", versions[0]));
                }
                else
                {
                    dlgComboPick picker = new dlgComboPick(versions.ToArray());
                    if (picker.ShowDialog() == DialogResult.OK)
                        selected = picker.mySelectedIndex;
                    else
                        selected = -1;
                }
                #endregion

                #region get values from the registry
                vsPath = "";
                installPath = "";
                sdkPath = "";
                try
                {
                    itemPath = productpath.OpenSubKey(versions[selected] + @"\Setup\VC");
                    vsPath = (String)itemPath.GetValue("ProductDir");
                    installPath = (String)productpath.OpenSubKey(versions[selected]).GetValue("InstallDir");
                    sdkPath = (string)Registry.LocalMachine.OpenSubKey(sdkSubkey).GetValue("CurrentInstallFolder");
                }
                catch { MessageBox.Show("Can't determine Visual Studio Path.Exiting"); Close(); }
                #endregion

                if (vsPath.EndsWith(@"\")) vsPath=vsPath.Remove(vsPath.Length - 1);
                #endregion

                String path = Environment.GetEnvironmentVariable("path");
                Environment.SetEnvironmentVariable("include", String.Format(@"{1}\INCLUDE;{0}\INCLUDE;", vsPath, sdkPath));
                Environment.SetEnvironmentVariable("lib", String.Format(@"{0}\ATLMFC\LIB;{0}\LIB;{1}\Lib", vsPath, sdkPath));
                // with a fresh install of VS2013 on a clean build of win7 i had to goto the registry and 
                //change HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows
                //CurrentInstallFolder from 
                // C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\ 
                //to
                // C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\
                // not sure what the deal is there...
                
                
                Environment.SetEnvironmentVariable("libpath", String.Format(@"{0}\ATLMFC\LIB;{0}\LIB;", vsPath));
                Environment.SetEnvironmentVariable("path", String.Format(@"{0};{1}\BIN;{2}\BIN;{3}",installPath,vsPath,sdkPath,path));
                Environment.SetEnvironmentVariable("WindowsSdkDir", String.Format(@"{0}",1));
            }
            #endregion

            //add tooltips to help users
            ToolTip myTT = new ToolTip();
            myTT.SetToolTip(this.chkListStuList, "List of students. Check the students you want to grade.");
            myTT.SetToolTip(this.txtMain, "this is where you can examine the students program and output.");
            myTT.SetToolTip(this.txtGrade, "this will show you the previous grade file if one exists.");
            myTT.SetToolTip(this.cmbProglist, "select the assignment you want to grade here.");



            //TODO(ben Viall): take this print statement out before releasing this
            //'debug and say that i loaded the form sucessfully
            System.Console.WriteLine("form1 loaded");
        }
        /// <summary>
        /// used to sort instances of class Student by last Name
        /// </summary>
        /// File
        public int CompareByLname(Student x, Student y)
        {
            return String.Compare(x.lName, y.lName);
        }

        private void LoadProgramDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgOpenProg.ShowDialog();
            myClassSection.getProgramList(dlgOpenProg.FileName);
            myClassSection.populateProglist(cmbProglist);
            //myClassSection.ProgPath = dlgOpenProg.FileName;
        }

        private void SaveProgramListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            dlgSaveProgList.ShowDialog();
            StreamWriter outfile = new StreamWriter(dlgSaveProgList.FileName);
            List<Assignment>.Enumerator csProg;
            outfile.WriteLine();
            csProg = Form1.myClassSection.assignments.GetEnumerator();
            while (csProg.MoveNext())
                outfile.WriteLine(csProg.Current.Serialize());

            outfile.Close();
            myClassSection.ProgPath = dlgSaveProgList.FileName;
             */
        }

        private void LoadListOfStudentsToolStripMenuItem_Click(object sender, EventArgs e)
        {

            //input format
            //username,lastname,firstname,labdayofweek,enrolled

            dlgOpenStudent.ShowDialog();
            //Form1.myClassSection.StuPath = dlgOpenStudent.FileName;
            try
            {
                Form1.myClassSection.getStudentList(dlgOpenStudent.FileName, true);
                myClassSection.populateStuList(chkListStuList, true);
            }
            catch (System.IO.IOException ex)
            {
                MessageBox.Show(ex.Message + "\n" + ex.StackTrace); // chances are this means the file is open somewhere else.
            }
            catch (ArgumentException ex)
            {
                MessageBox.Show(ex.Message + "\n"+ ex.StackTrace); // chances are the user left a header line in the data file.
            }
        }

        private void SaveStudentListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            dlgSaveStuList.ShowDialog();
            StreamWriter outfile = new StreamWriter(dlgSaveStuList.FileName);
            ClassSection cs = Form1.myClassSection;
            List<Student>.Enumerator stuEnumerator;

            cs.students.Sort(CompareByLname);
            stuEnumerator = cs.students.GetEnumerator();
            while (stuEnumerator.MoveNext())
                outfile.WriteLine(stuEnumerator.Current.serialize());
            outfile.Close();
            Form1.myClassSection.ProgPath = dlgSaveStuList.FileName;
             */
        }

        private void ChooseHomeFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            fldrLocalDir.ShowDialog();
            try
            {
                //now setup the folders needed to run properly 
                //(Note: we should still check later)
                //TODO(Ben Viall):create Photo dir
                if (!Directory.Exists(myClassSection.pf.localPhotoDir()))
                    Directory.CreateDirectory(myClassSection.pf.localPhotoDir());
                myClassSection.pf.localDir = fldrLocalDir.SelectedPath;
                lblLocalDir.Text = myClassSection.pf.localDir;
                Assignment.localDir = myClassSection.pf.localDirExpanded;
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
            }
        }

        private void ChoseRemoteFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            fldrRemoteDir.ShowDialog();
            myClassSection.pf.RemoteDir = fldrRemoteDir.SelectedPath;
            lblRemoteDir.Text = myClassSection.pf.RemoteDir;
            //Assignment.remoteDir = myClassSection.pf.RemoteDir
        }

        /// <summary>
        /// store the Settings file in the local directory
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <remarks> data:
        /// local Dir
        /// remote Dir
        /// student list file
        /// program list File</remarks>
        private void SaveSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //check that all 4 settings exist
            //if (!File.Exists(myClassSection.StuPath)) { MessageBox.Show("select a student File"); return; }
            //if (!File.Exists(myClassSection.ProgPath)) { MessageBox.Show("select a Program File"); return; }
            if (!Directory.Exists(myClassSection.pf.localDirExpanded)) { MessageBox.Show("select a Local Directory"); return; }
            if (!Directory.Exists(myClassSection.pf.RemoteDirExpanded)) { MessageBox.Show("select a RemoteDirectory"); return; }
            Form1.myClassSection.storeToFile(Form1.myClassSection.pf.localDirExpanded + "\\graderSettings.xml");
        }

        private void OpenSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult x = dlgOpenSettings.ShowDialog();
            //VPNRunning()
            if (x == DialogResult.OK)
            {
                myClassSection.restoreFromFile(dlgOpenSettings.FileName, true);
                myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
                myClassSection.populateProglist(cmbProglist);
                lblLocalDir.Text = Form1.myClassSection.pf.localDirExpanded;
                lblRemoteDir.Text = Form1.myClassSection.pf.RemoteDirExpanded;
                Assignment.localDir = Form1.myClassSection.pf.localDirExpanded;
                //Assignment.remoteDir = Form1.myClassSection.pf.RemoteDir
                chkListStuList.SelectedIndex = 0;
                cmbProglist.SelectedIndex = cmbProglist.Items.Count - 1;
            }
        }

        private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void SelectAllToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < chkListStuList.Items.Count; i++)
                chkListStuList.SetItemCheckState(i, CheckState.Checked);
        }

        private void SelectNoneToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < chkListStuList.Items.Count; i++)
                chkListStuList.SetItemCheckState(i, CheckState.Unchecked);
        }

        private void SelectByLabToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool result;
            DayOfWeek day;
            day= (DayOfWeek)Enum.Parse(typeof(DayOfWeek), ((ToolStripMenuItem)sender).Text);
            for (int i = 0; i < chkListStuList.Items.Count; i++)
            {
                result = myClassSection.students[i].isSection(day);
                chkListStuList.SetItemChecked(i, result);
            }
        }

        private void SelectGradeToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            selectbyGrade(txtToolStripGrade.Text);
        }

        private void selectbyGrade(string grade)
        {

            Student stu;
            bool result;
            for (int i = 0; i < chkListStuList.Items.Count; i++)
            {
                stu = ((Student)chkListStuList.Items[i]);
                result = int.Equals(myClassSection.grade(stu, myClassSection.currentAssignment), int.Parse(grade));
                chkListStuList.SetItemChecked(i, result);
            }
        }
        private void SelectInversToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool result;
            for (int i = 0; i < chkListStuList.Items.Count; i++)
            {
                result = chkListStuList.GetItemChecked(i);
                chkListStuList.SetItemChecked(i, !result);
            }
        }

        private void SelectUngradedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //TODO(BenViall): refocator to use an iterator
            for (int i = 0; i < chkListStuList.Items.Count; i++)
                if (myClassSection.grade((Student)chkListStuList.Items[i], myClassSection.currentAssignment) == int.MinValue)
                    chkListStuList.SetItemCheckState(i, CheckState.Checked);
                else
                    chkListStuList.SetItemCheckState(i, CheckState.Unchecked);
        }

        private void AddStudentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgStudent x = new dlgStudent(new Student());         //Create a dialog with a blank student
            DialogResult result = x.ShowDialog();                 //show and then the user edit it
            if (result == DialogResult.OK)          //add to list and repopulate the listbox
            {
                myClassSection.students.Add(x.myStu);
                myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
            }
        }

        private void EditSelectedStudentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result;
            dlgStudent x = new dlgStudent(Form1.myClassSection.students[chkListStuList.SelectedIndex]);
            result = x.ShowDialog();
            if (result == DialogResult.OK)
            {
                myClassSection.students.RemoveAt(chkListStuList.SelectedIndex);
                myClassSection.students.Insert(chkListStuList.SelectedIndex, x.myStu);
                myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
            }
        }

        private void WithDrawFromClassToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int index = chkListStuList.SelectedIndex;
            Form1.myClassSection.students[index].Withdrawn = true;
            Form1.myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
        }

        private void ReenrollSelectedInClassToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int index = chkListStuList.SelectedIndex;
            Form1.myClassSection.students[index].Withdrawn = false;
            Form1.myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
        }

        private void AddAssignmentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result;
            dlgProgram x = new dlgProgram(new Assignment()); // start with a template assigment the user can edit
            result = x.ShowDialog();
            if (result == DialogResult.OK) // only add assignment if the user clicks "OK"
            {
                myClassSection.assignments.Add(x.prog);
                myClassSection.populateProglist(cmbProglist);
            }
            //TODO: save the program list to the prog file listed in the setings 
            //      immediately after editing or adding a program

            /*
             * if (myClassSection.ProgPath != "")
            {
                StreamWriter outfile = new StreamWriter(myClassSection.ProgPath);
                List<Assignment>.Enumerator csProg;
                outfile.WriteLine();
                csProg = Form1.myClassSection.assignments.GetEnumerator();
                while (csProg.MoveNext())
                    outfile.WriteLine(csProg.Current.Serialize());

                outfile.Close();
            }
             */
        }

        private void EditSelectedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgProgram x = new dlgProgram(myClassSection.currentAssignment);
            DialogResult result = x.ShowDialog();
            myClassSection.currentAssignment = x.prog;
            //now update the Program file
            SaveSettingsToolStripMenuItem_Click(sender, e);
            /*
            StreamWriter outfile = new StreamWriter(myClassSection.ProgPath);
            List<Assignment>.Enumerator csProg;
            outfile.WriteLine();
            csProg = Form1.myClassSection.assignments.GetEnumerator();
            while (csProg.MoveNext())
                outfile.WriteLine(csProg.Current.Serialize());
            outfile.Close();
            */
        }

        private void DownloadSourcesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //TODO(Ben Viall): Follow this clusterfuck and figure out what arguments need to be passed
            //                 and only pass those arguments
            //setup the progresss bar output

            dlgOutput = new dlgProgress(bkgDownload);
            dlgOutput.Visible = true;
            dlgOutput.Show();
            dlgOutput.BringToFront();
            // give the background task the checklist
            // so it can see which students to download
            this.bkgDownload.RunWorkerAsync((chkListStuList));
        }



        private void CompileSourcesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //TODO(Ben Viall): Follow this clusterfuck and figure out what arguments need to be passed
            //                 and only pass those arguments

            if (chkListStuList.CheckedItems.Count > 1 && chkAutoDelete.Checked==false )
            {
                MessageBox.Show("auto delete must be turned on for multi Run");
                chkAutoDelete.Checked = true;
            }
            dlgOutput = new dlgProgress(bkgCompile);
            dlgOutput.Visible = true;
            dlgOutput.Show();
            dlgOutput.BringToFront();

            Hashtable arg = new Hashtable(2);
            List<Student> compileList=new List<Student>();

            copyCollectionToList(chkListStuList.CheckedItems, compileList);
            
            arg.Add("list", compileList);
            arg.Add("section", myClassSection);

            bkgCompile.RunWorkerAsync(arg);
            //'Form1.myClassSection.runPrograms(chkListStuList, dlgOutput)
        }


        private void copyCollectionToList(CheckedListBox.CheckedItemCollection src,List<Student> dest)
        {
            IEnumerator e = src.GetEnumerator();
            dest.Clear();
            while (e.MoveNext())
            {
                dest.Add(new Student((Student)e.Current));
            }
        }

        private void GradeSourcesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (chkListStuList.CheckedItems.Count == 0)
            {
                MessageBox.Show("no students selected");
                return;
            }
            chkListStuList.SelectedIndex = chkListStuList.Items.IndexOf(chkListStuList.CheckedItems[0]);
            DisplayProgram(((Student)chkListStuList.CheckedItems[0]), myClassSection.currentAssignment);
        }

        private void UploadGradesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //TODO: change this to call the background worker instead
            dlgOutput = new dlgProgress(bkgUpload);
            dlgOutput.Visible = true;
            dlgOutput.Show();
            dlgOutput.BringToFront();

            Hashtable arg = new Hashtable(2);

            arg.Add("list", chkListStuList.CheckedItems);
            arg.Add("section", myClassSection);

            bkgUpload.RunWorkerAsync(arg);
            //myClassSection.uploadGrades(chkListStuList);
        }

        private void EmailAssignmentGradeToCheckedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            String destemail;
            String subject, message;
            //Student stu;
            Assignment prog;
            int grade;
            prog = myClassSection.currentAssignment;
            subject = prog.dispName + " has been graded.";

            foreach (Student stu in chkListStuList.CheckedItems)
            {
                if (File.Exists(Form1.myClassSection.pf.gradePath(stu, prog, PathFinder.Local)))
                {
                    grade = myClassSection.grade(stu, prog);

                    destemail = stu.userName + "@umassd.edu";
                    message = "your submission for " + prog.dispName + " has been graded.\n" +
                              "you recieved " + grade.ToString() + " out of 100. details can be found in the class directory." +
                              " To request a regrade reply to this email with the following format in the subject line\n" +
                              "[ECE264 - Lab ## - Last, First - Lab Name - (resubmit or Late)]\n" +
                              "In the email body, you should explain what you think the problem is.";
                    sendEmail(destemail, subject, message);
                }
            }

            MessageBox.Show("emails have been sent");
        }

        private void sendEmail(String dest, String subj, String msg)
        {
            MailAddress fromADDR, toADDR;
            SmtpClient smtpClient;
            MailMessage message;

            smtpClient = new SmtpClient("smtp.gmail.com");
            smtpClient.Port = 587;
            smtpClient.EnableSsl = true;
            smtpClient.Credentials = new NetworkCredential(toolStriptxtEmailFrom.Text, ToolStriptxtEmailPassword.Text);

            fromADDR = new MailAddress(toolStriptxtEmailFrom.Text, "The Grader");
            toADDR = new MailAddress(dest);

            message = new MailMessage();

            message.From = fromADDR;
            message.To.Add(toADDR);
            message.Subject = subj;
            message.Body = msg;

            try
            {
                smtpClient.EnableSsl = true;
                smtpClient.Send(message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        private void CopyGradesToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.Clear();
            DialogResult a = MessageBox.Show("would you like the names as well?", "Option", MessageBoxButtons.YesNo);
            if (a == DialogResult.Yes)
                Clipboard.SetText(getCSVgrades(true));
            else
                Clipboard.SetText(getCSVgrades(false));
        }

        /// <summary>
        /// queury the data files and collect grades of the current project
        /// and returns the resulting string
        /// </summary>
        /// <param name="withNames">if true, stores name grade pairs,if false only grades</param>
        /// <returns>the CSV compliant string</returns>
        public string getCSVgrades(bool withNames)
        {
            String clipboardText = "";
            int grade;
            List<Student>.Enumerator stuEnum;
            Assignment prog = myClassSection.currentAssignment;
            //header
            if (withNames) clipboardText += "Student\t";
            clipboardText += prog.dispName + "\n";

            stuEnum = myClassSection.students.GetEnumerator();
            while (stuEnum.MoveNext())
            {
                grade = myClassSection.grade(stuEnum.Current, prog);
                if (withNames) clipboardText += stuEnum.Current.userName + "\t";
                if (grade != -1) clipboardText += grade.ToString();
                else clipboardText += "not graded";

                clipboardText += "\n";
            }
            return clipboardText;
        }


        private void EditSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void bkgDownload_DoWork(object sender, DoWorkEventArgs e)
        {
            myClassSection.downloadFiles(((CheckedListBox)e.Argument), bkgDownload, false);
        }

        private void bkgDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            dlgOutput.Hide();
            MessageBox.Show("download complete");
        }

        private void bkgDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            dlgOutput.BringToFront();
            dlgOutput.Focus();
            dlgOutput.progressBar.Value = e.ProgressPercentage;
            dlgOutput.lblStatus.Text = e.UserState.ToString();
        }

        private void bkgCompile_DoWork(object sender, DoWorkEventArgs e)
        {
            //myClassSection.runPrograms(e.Argument, dlgOutput)
            Hashtable arg;
            arg = (Hashtable)e.Argument;
            myClassSection = (ClassSection)arg["section"];
            
            List<Student> a = (List<Student>)arg["list"];
            
            
            myClassSection.runPrograms(ref a, myClassSection.currentAssignment, bkgCompile, false,chkAutoDelete.Checked);
        }

        private void bkgCompile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            dlgOutput.Hide();
            MessageBox.Show("Compile complete");
        }

        private void cmdGrd_Click(object sender, EventArgs e)
        {
            //get grade
            int grade;
            // the sender is either a button or a textbox. 
            //figure out what it is then typecast it acordingly
            try
            {
                if (sender.GetType() == typeof(System.Windows.Forms.Button))
                    grade = int.Parse(((System.Windows.Forms.Button)sender).Text);
                else
                    grade = int.Parse(((System.Windows.Forms.TextBox)sender).Text);
            }
            catch (Exception ex)
            {
                string temp;
                if (sender.GetType() == typeof(System.Windows.Forms.Button))
                    temp = ((System.Windows.Forms.Button)sender).Text;
                else
                {
                    temp = ((System.Windows.Forms.TextBox)sender).Text;
                    ((System.Windows.Forms.TextBox)sender).Text="0";
                }
                MessageBox.Show(string.Format("{0} is not a valid grade...",temp));
                return;
            }


            //grade the student for the current program
            GradeIt(ref myClassSection.CurrentStudent, ref myClassSection.currentAssignment, grade);
            if (chkAutoAdvance.Checked == true) cmdNext_Click(sender, e);
        }

        /// <param name="grade">grade the student earned ( not the grade you want to give the little bastards)</param>
        /// <param name="stu">the student who earned the grade</param>
        /// <param name="prog">the program the student earned the grade on</param>
        public void GradeIt(ref Student stu, ref Assignment prog, int grade)
        {
            String s;

            s = txtMain.Text;
            int grdPosition = s.IndexOf("@@@");


            if (grdPosition > 0)
            {
                s = s.Remove(grdPosition, 3);
                s = s.Insert(grdPosition, grade.ToString());
                try
                {
                    StreamWriter grdFile = new StreamWriter(myClassSection.pf.gradePath(stu, prog, PathFinder.Local));
                    grdFile.Write(s);
                    grdFile.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.StackTrace);
                    return;
                }
            }
        }

        private void chkShowWithdrawn_CheckedChanged(object sender, EventArgs e)
        {
            Form1.myClassSection.populateStuList(chkListStuList, chkShowWithdrawn.Checked);
        }

        private void cmbProglist_SelectedIndexChanged(object sender, EventArgs e)
        {
            myClassSection.currentAssignment = myClassSection.assignments[cmbProglist.SelectedIndex];
            tslblCurrentProg.Text = myClassSection.currentAssignment.dispName;
            DisplayProgram(myClassSection.CurrentStudent, myClassSection.currentAssignment);
        }

        private void chkListStuList_SelectedIndexChanged(object sender, EventArgs e)
        {
            Student stu = ((Student)chkListStuList.SelectedItem);
            //find the index of the listbox
            if (stu == null) return;
            myClassSection.CurrentStudent = stu;
            tslblCurrentStudent.Text = stu.userName;
            DisplayProgram(stu, myClassSection.currentAssignment);
        }


        /// <summary>
        /// get data about the currently selected student's project submission and show the user
        /// </summary>
        private void DisplayProgram(Student stu, Assignment prog)
        {

            StreamReader infile;

            // 3 steps
            // 1) display picture
            // 2) display prn File
            // 3) display previous grd file

            if (stu == null)
            {
                //MessageBox.Show("you are trying to display a student that doesnt exist??");
                return;
            }
            if (prog == null)
            {
                //MessageBox.Show("you are trying to display a program that doesnt exist??");
                return;
            }

            //display the photo if it exists
            String photoPath = myClassSection.pf.photoPath(stu, PathFinder.Local);
            try
            {
                picStuPic.Load(photoPath);
            }
            catch (Exception)
            {
                picStuPic.Image = UmassGrader.Properties.Resources.noPhoto;
            }
            

            #region find lateness
            string submitFilePath;
            DateTime submitted,due;
            int late = 0;
            switch (stu.LabSection)
            {
                case DayOfWeek.Monday: due = prog.DueM; break;
                case DayOfWeek.Tuesday: due = prog.DueT; break;
                case DayOfWeek.Wednesday: due = prog.DueW; break;
                case DayOfWeek.Thursday: due = prog.DueR; break;
                case DayOfWeek.Friday: due = prog.DueF; break;
                default: due = prog.DueM; break;
            }
            due = due.AddHours(23);
            due = due.AddMinutes(59);
            due = due.AddSeconds(59);
            for (int i = 0; i < myClassSection.currentAssignment.submitList.Count; i++)
            {
                submitFilePath = myClassSection.pf.submitablesPath(stu, prog, i, PathFinder.Local);
                if (File.Exists(submitFilePath))
                {
                    submitted = File.GetLastWriteTime(submitFilePath);
                    if (submitted > due)
                    {
                        if ((((submitted - due).Days) + 1) > late)
                            late = (((submitted - due).Days) + 1);
                    }
                }
            }

            lblLate.Text = string.Format("Late By:{0} Days", late);
            
            #endregion
            // display prn Files
            if (!File.Exists(myClassSection.pf.printPath(stu, prog)))
            {
                txtMain.Text = "YOU HAVENT RUN THIS PROGRAM YET\r\n";
                txtMain.Text += "-------------------------------\r\n";
                //see if we can show the files if they have been downloaded
                
                for (int i = 0; i < myClassSection.currentAssignment.submitList.Count; i++)
                {
                    submitFilePath = myClassSection.pf.submitablesPath(stu, prog, i, PathFinder.Local);
                    if (File.Exists(submitFilePath))
                    {
                        txtMain.Text += prog.submitList[i] + ":\r\n";
                        // display the file if its not a jpg...
                        // TODO(Ben Viall): find a better way to figure out if a submited file 
                        // is a file we can show in a textbox
                        if (!submitFilePath.EndsWith(".jpg"))
                        {
                            infile = new StreamReader(submitFilePath);
                            //Dim dos As System.Text.Encoding = System.Text.Encoding.GetEncoding(37)
                            txtMain.Text += infile.ReadToEnd().Replace("\r\n", "\n").Replace("\n", "\r\n");
                            infile.Close();
                        }
                        else
                        {
                            txtMain.Text += "\tFILE NOT FOUND\r\n";
                        }
                    }
                }
            }
            else
            {
                try
                {
                    // use exteded ascii encodeing for ascii art lovers
                    System.Text.Encoding encoding = System.Text.Encoding.GetEncoding(437);
                    infile = new StreamReader(myClassSection.pf.printPath(stu, prog),encoding);
                    txtMain.Text = infile.ReadToEnd().Replace("\r\n", "\n").Replace("\n", "\r\n");
                    infile.Close();
                }
                catch { MessageBox.Show("cant open prn file"); }
            }

            // goto the correct section of the prn file
            if (gotoCode.Checked) gotoSection("** start file **", 0);
            if (gotoComment.Checked) gotoSection("Comments:", 1);
            if (gotoCompiler.Checked) gotoSection("** compiled *", 0);
            if (gotoOutput.Checked) gotoSection("** Run  1**", 0);

            //finally display the previous grd file
            string grdpath = myClassSection.pf.gradePath(stu, prog, PathFinder.Local);
            int readsize = 50 * 1024;
            if (File.Exists(grdpath))
            {
                
                infile = new StreamReader(myClassSection.pf.gradePath(stu, prog, PathFinder.Local));
                if (new FileInfo(grdpath).Length > readsize)
                {
                    char[] buf = new char[readsize + 1];
                    infile.Read(buf, 0, readsize);
                    txtGrade.Text = buf.ToString(); // if this doesnt work try
                    //txtGrade.Text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(buf));
                    txtGrade.Text = txtGrade.Text + "\n\n** File Truncated **\n\n";
                }
                else
                {
                    txtGrade.Text = infile.ReadToEnd();
                }
                infile.Close();
            }
            else
            {
                txtGrade.Text = "No previous grade file.";
            }




        }

        private void goto_Click(object sender, EventArgs e)
        {
            if (gotoCode.Checked) gotoSection("** start file **", 0);
            if (gotoComment.Checked) gotoSection("Comments:", 1);
            if (gotoCompiler.Checked) gotoSection("** compiling **", 0);
            if (gotoOutput.Checked) gotoSection("** Run  1**", 0);
        }


        /// <summary>
        /// this will move the cursor of the main txtbox to a specific part of the -grd.txt file
        /// </summary>
        private void gotoSection(String key, int from)
        {
            int x;
            if (from == 1)
                txtMain.Select(0, 0);
            else
                txtMain.Select(Math.Max(0,txtMain.TextLength - 1), 0);

            txtMain.ScrollToCaret();
            x = txtMain.Text.IndexOf(key);
            if (x > 0)
            {
                txtMain.Select(x + key.Length, 0);
                txtMain.ScrollToCaret();
                txtMain.Select();
            }
        }

        private void cmdPrev_Click(object sender, EventArgs e)
        {
            int currentSelected = chkListStuList.SelectedIndex;
            int nextSelected = currentSelected - 1;
            while (!chkListStuList.CheckedIndices.Contains(nextSelected) && nextSelected >= 0)
                nextSelected--;
            if (nextSelected < 0)
                nextSelected = currentSelected;

            chkListStuList.SelectedIndex = nextSelected;
        }

        private void cmdNext_Click(object sender, EventArgs e)
        {
            int oldSelected = chkListStuList.SelectedIndex;
            int currentSelected = chkListStuList.CheckedItems.IndexOf(chkListStuList.SelectedItem);

            if (currentSelected == -1 && chkListStuList.CheckedIndices.Count >= 1)
            {
                // this is not found in the list of checked items.
                chkListStuList.SelectedIndex = chkListStuList.CheckedIndices[0];
                return;
            }

            if (currentSelected + 1 < chkListStuList.CheckedIndices.Count)
            {
                chkListStuList.SelectedIndex = chkListStuList.CheckedIndices[currentSelected + 1];
                return;
            }
            //no change

        }


        /// <summary>
        /// little helper function to repeat a character over and over again
        /// </summary>
        public static String repeatchar(char c, int num)
        {
            String val;
            int i;
            //safety check 
            if (num > 255) num = 255;
            val = "";
            for (i = 0; i < num; i++)
                val += c;

            return val;
        }

        private void bkgUpload_DoWork(object sender, DoWorkEventArgs e)
        {
            // upload all -grd.txt files.
            Hashtable myHash = ((Hashtable)e.Argument);
            myClassSection.uploadGrades((CheckedListBox.CheckedItemCollection) myHash["list"], (BackgroundWorker)sender);
        }

        private void bkgUpload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            dlgOutput.Hide();
            MessageBox.Show("Upload Complete");
        }

        private void SplitContainer4_Panel2_Paint(object sender, PaintEventArgs e)
        {

        }

        private void testToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //test to serialize prog
            Assignment a = myClassSection.currentAssignment;
            MemoryStream ms = new MemoryStream();
            XmlSerializer  xmlF = new XmlSerializer(typeof(ClassSection));
            xmlF.Serialize(ms, myClassSection);
            ms.Seek(0, SeekOrigin.Begin);
            using (StreamReader SR = new StreamReader(ms))
            {
                
                String temp = SR.ReadToEnd();

                this.txtMain.Text = temp;
            }

        }

        private void contextMenuStripChangeGradeVal_Opening(object sender, CancelEventArgs e)
        {
            if (sender.GetType() == typeof(ContextMenuStrip))
            {
                ContextMenuStrip  cm = (ContextMenuStrip)sender;
                if (cm.SourceControl.GetType() == typeof(Button))
                {
                    Button b = (Button)cm.SourceControl;
                    toolStripTextBoxNewGrade.Text = b.Text;
                }
            }
        }

        private void toolStripTextBoxNewGrade_KeyDown(object sender, KeyEventArgs e)
        {
            int i=0;
            if (e.KeyCode != Keys.Enter) return;
            object p =((ToolStripTextBox)sender).GetCurrentParent();
            if (p.GetType() == typeof(ContextMenuStrip))
            {
                ContextMenuStrip cms = (ContextMenuStrip)p;
                cms.SourceControl.Text = ((ToolStripTextBox)sender).Text;
                cms.Close();
            }

        }

        private void contextMenuStripChangeGradeVal_Closing(object sender, ToolStripDropDownClosingEventArgs e)
        {
            string[] btnList = new string[19];
            for (int i = 0; i < myGrdButtons.Count; i++)
            {
                btnList[i] = myGrdButtons[i].Text;
            }
            Settings.Default.grdButtons= string.Join(",", btnList);
            Settings.Default.Save();
        }

        private void launchCmdPromptToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process cmd = new Process();
            ProcessStartInfo si = new ProcessStartInfo("cmd", string.Format(@"/K set prompt=\$G && cd {0}\{1} && cd", myClassSection.pf.localDirExpanded, myClassSection.currentAssignment.dispName));
            cmd.StartInfo = si;
            cmd.Start();
        }

        private void AssignmentToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void selectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            selectbyGrade(toolStripTextBox1.Text);
        }

        private void rerunSelectedStudentONLYToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (chkListStuList.SelectedItems.Count != 1)
            {
                MessageBox.Show("more than one student is selected. this is odd. not grading...");
                return;
            }
            dlgOutput = new dlgProgress(bkgCompile);
            dlgOutput.Visible = true;
            dlgOutput.Show();
            dlgOutput.BringToFront();

            Hashtable arg = new Hashtable(2);
            List<Student> compileList = new List<Student>();

            compileList.Add((Student)chkListStuList.SelectedItem);

            arg.Add("list", compileList);
            arg.Add("section", myClassSection);

            bkgCompile.RunWorkerAsync(arg);
        }

        private void debugStudentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process dbg = new Process();
            dbg.StartInfo = new ProcessStartInfo("DevEnv", "/DebugExe " + "jpepper.exe");
            
        }

        private void txtProgTimeout_TextChanged(object sender, EventArgs e)
        {

        }

        private void chkWAR_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Default.WaitAfterRun = (sender as CheckBox).Checked;
            Settings.Default.Save();
            myClassSection.war = Settings.Default.WaitAfterRun;
        }

        private void txtWARms_TextChanged(object sender, EventArgs e)
        {
            Settings.Default.WaitAfterRunMS = int.Parse((sender as TextBox).Text);
            Settings.Default.Save();
            myClassSection.warMS = Settings.Default.WaitAfterRunMS;
        }

        /// <summary>
        /// generates a zip file to be submited to the SID plagurism site for analysis.
        /// uses the IONIC zip library
        /// SID:http://software.bioinformatics.uwaterloo.ca/SID/servlets/IndexPage
        /// ionic zip library:http://dotnetzip.codeplex.com/
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateComparisonDirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
            string baseCmp = String.Format(@"{0}\compare", myClassSection.pf.localDir);
            string srcName;
            if (!Directory.Exists(baseCmp))
                Directory.CreateDirectory(baseCmp);
            

            using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
            {
                foreach (Student stu in myClassSection.students)
                {
                    for (int i = 0; i < myClassSection.currentAssignment.submitList.Count; i++)
                    {
                        srcName = myClassSection.pf.compilablesPath(stu, myClassSection.currentAssignment, i, PathFinder.Local);
                        if (File.Exists(srcName))
                            zip.AddFile(srcName, stu.userName);
                    }
                }
                zip.Save(String.Format(@"{0}\{1}.zip", baseCmp, myClassSection.currentAssignment.dispName));


            }
             */
        }

        private void GenerateStudentsFromRemoteDirToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void ShowtempToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void dlgOpenStudent_FileOk(object sender, CancelEventArgs e)
        {

        }

        private void quickCopyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.Clear();
            Clipboard.SetText(getCSVgrades(false));
        }

    







    }
}